/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package MyThread;

import MyLib.Comvar;
import MyLib.MyFile;
import MyLib.MyPacket;
import Object.Torrent;
import XML.DOMUtil;
import java.io.File;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.SocketTimeoutException;
import java.util.ArrayList;
import java.util.Random;
import javax.swing.JTable;

/**
 *
 * @author QuangHau
 */
public class DownloadChunk extends Thread {

    String fileID;
    String chunkID;
    String hash;
    InetAddress ipAddress;
    byte[] chunk;
    Torrent torrenFile;
    JTable tbChunk;
    int row;
    boolean stopThread = false;

    DownloadChunk(Torrent _torrenFile, int _chunkID, JTable _tbChunk, int _row) {
        torrenFile = _torrenFile;
        chunkID = torrenFile.getChunks().get(_chunkID).getId();
        hash = torrenFile.getChunks().get(_chunkID).getHash();
        fileID = torrenFile.getId();
        tbChunk = _tbChunk;
        row = _row;
    }

    public void run() {
        Comvar.writeLog(1, DownloadChunk.class.getName(), "BEGIN DOWNLOAD CHUNK " + chunkID + " OF FILE " + torrenFile.getName() + "ID: " + torrenFile.getId());
        try {
            String stSend;
            String stRcv;
            //************************* khoi tao socket*****************************
            int ServerPort = 35617;
            ArrayList<byte[]> lst = new ArrayList<byte[]>();
            while (!stopThread) {
                boolean flag = false;
                DatagramSocket socket = new DatagramSocket();
                Random rd = new Random();
                int indexIP = rd.nextInt(Comvar.listChunkIP.get(Integer.parseInt(chunkID)).size());
                ipAddress = Comvar.listChunkIP.get(Integer.parseInt(chunkID)).get(indexIP);
                lst.clear();

                synchronized (tbChunk) {
                    tbChunk.setValueAt(ipAddress.getHostAddress(), row, 2);
                    tbChunk.setValueAt("Downloading...", row, 3);
                }

                //************************* Xin download chunk*****************************
                //Gói tin yêu cầu download chunk
                stSend = fileID + ";" + chunkID;
                byte option = 0;
                byte typeHeader = 100;
                DatagramPacket sendPacket = MyPacket.createPacket(stSend.getBytes(), ipAddress, ServerPort, typeHeader, option, 0, 0);

                //Gói tin nhận kêt quả yêu cầu download chunk
                byte[] data_Recv = new byte[1024];
                DatagramPacket packet = new DatagramPacket(data_Recv, data_Recv.length);

                //Gửi yêu cầu - bật đồng hồ
                socket.send(sendPacket);
                Comvar.writeLog(3, DownloadChunk.class.getName(), "SEND " + sendPacket.getAddress().getHostAddress() + 
                        ":" + sendPacket.getPort() +  " [Request download chunk " + stSend + "]");
                System.out.println("xin down load chunk " + stSend + " bang port " + sendPacket.getPort());



                socket.setSoTimeout(3000);
                try {
                    // Nhận kết quả - chuyển download chunk
                    socket.receive(packet);
                    MyPacket packetRecv = new MyPacket(packet);
                    stRcv = new String(packetRecv.getData(), 0, packetRecv.getData().length);
                    Comvar.writeLog(3, DownloadChunk.class.getName(), "RECEIVE " + packet.getAddress().getHostAddress() + 
                        ":" + packet.getPort() +  " [Accept download chunk " + stSend + "]");
                    System.out.println("Nhan đong ý cua server : " + packet.getAddress().getHostAddress() + " port " + packet.getPort() + " data " + stRcv);

                    //Gửi lại goi tin xác nhận bắt đầu quá tình down load
                    sendPacket = MyPacket.createPacket(stSend.getBytes(), packet.getAddress(), packet.getPort(), typeHeader, option, 0, 0);
                    socket.send(sendPacket);
                    Comvar.writeLog(3, DownloadChunk.class.getName(), "SEND " + packet.getAddress().getHostAddress() + 
                        ":" + packet.getPort() +  " [Accept download chunk " + stSend + "]");
                    System.out.println("Gui lai xac nhan down load");

                    //************************* Download chunk *****************************
                    socket.setSoTimeout(3000);
                    int ack = 0;
                    int total = 0;
                    do {
                        //Nhân dữ liệu   
                        try {
                            byte[] rcvbuf = new byte[1024];
                            DatagramPacket rcv_packet = new DatagramPacket(rcvbuf, rcvbuf.length);
                            socket.receive(rcv_packet);
                            MyPacket packetDataRecv = new MyPacket(rcv_packet);
                            Comvar.writeLog(3, DownloadChunk.class.getName(), "RECEIVE " + rcv_packet.getAddress().getHostAddress() + 
                        ":" + rcv_packet.getPort() +  " [DATA SEQ: "+packetDataRecv.getSyn()+" OF CHUNK "+ stSend +"]");
                            System.out.println("Nhan data: " + packetDataRecv.getData() + " seq " + packetDataRecv.getSyn());

                                                       
                            if (packetDataRecv.getFlag() == 4) {
                                //down load xong
                                chunk = new byte[total];
                                int index = 0;
                                for (int i = 0; i < lst.size(); i++) {
                                    System.arraycopy(lst.get(i), 0, chunk, index, lst.get(i).length);
                                    index += lst.get(i).length;
                                }
                                if (MyFile.generateBufferedHash(chunk).equals(hash)) {
                                    flag = true;
                                } else {
                                    flag = false;
                                }
                                break;
                            }
                            
                            //kiem tra checksum
                            short checksum = MyPacket.checksum(packetDataRecv.getData(), packetDataRecv.getData().length);
                            
                            //lưu trữ dữ liệu neu thoa
                            if (ack == packetDataRecv.getSyn() && packetDataRecv.getChecksum() == checksum) {
                                //dung goi tin can nhan
                                lst.add(packetDataRecv.getData());
                                ack += packetDataRecv.getData().length;
                                total += packetDataRecv.getData().length;
                            }

                            //Gửi ACK
                            option = 1;
                            typeHeader = 100;
                            DatagramPacket sendPacketACK = MyPacket.createPacket(stSend.getBytes(), packet.getAddress(), packet.getPort(), typeHeader, option, 0, ack);
                            socket.send(sendPacketACK);
                            Comvar.writeLog(3, DownloadChunk.class.getName(), "SEND " + rcv_packet.getAddress().getHostAddress() + 
                                ":" + rcv_packet.getPort() +  " [ACK: " + ack + " OF CHUNK " + stSend +"]");
                            System.out.println("gui lai ack " + ack);


                        } catch (SocketTimeoutException e) {
                            //Het time out ,  nối file thu -> chay lai tien trinh xin down load
                            chunk = new byte[total];
                            int index = 0;
                            for (int i = 0; i < lst.size(); i++) {
                                System.arraycopy(lst.get(i), 0, chunk, index, lst.get(i).length);
                                index += lst.get(i).length;
                            }
                            if (MyFile.generateBufferedHash(chunk).equals(hash)) {
                                flag = true;
                            } else {
                                flag = false;
                            }
                            break;
                        }

                    } while (!stopThread);

                    if (flag) {
                        System.out.println("DOWN LOAD XONG - GHI CHUNK");
                        String path = "Data\\" + fileID;
                        File file = new File(path);
                        if (!file.exists()) {
                            file.mkdirs();
                        }
                        path += "\\" + chunkID + ".chunk";
                        MyFile.write(chunk, path);

                        //************************* Update database *****************************
                        DOMUtil.insertChunk(torrenFile, chunkID); 
                        socket.close();
                        break;
                    }
                    
                    
                } catch (SocketTimeoutException e) {
                    //socket.close();
//                    //Hết  time out - gửi lại
//                    System.out.println("Hết time out -- gửi lại");
//                    socket.send(sendPacket);
//                    System.out.println("xin down load chunk " + stSend + " bang port " + sendPacket.getPort());
//                    socket.setSoTimeout(1000);
                }
                socket.close();
            }
        } catch (Exception e) {
            e.printStackTrace();
        }

        synchronized (tbChunk) {
            if (stopThread) {
                tbChunk.setValueAt("Stopped", row, 3);
            } else {
                tbChunk.setValueAt("Downloaded", row, 3);
            }
        }
        Comvar.threadDownloadFile.release();
        System.out.println("EXIT DOWNLOAD CHUNK " + chunkID + " THREAD");
        Comvar.writeLog(1, DownloadChunk.class.getName(), "END DOWNLOAD CHUNK " + chunkID + " OF FILE " + torrenFile.getName() + "ID: " + torrenFile.getId());
    }

    public void stopDownloadChunk() {
        stopThread = true;
    }

    public boolean getDownloadChunk() {
        return stopThread;
    }
}
